#include <iostream>
#include "fasttrie.h"
#include "walker.h"

struct TEmpty{};
typedef TFastTrie<char, unsigned int, TEmpty>   TCP1251Trie;
typedef TPathTraits<TCP1251Trie>                TCP1251TriePathTraits;

struct TPathPrinter {
    TPathPrinter(const TCP1251Trie& trie)
    : Trie(trie)
    {}

    void HandlePath( const TCP1251TriePathTraits::TPath& path )
    {
        if (1 == path.size()) {
            return;
        }

        std::vector<unsigned int>   endings(0, 0);
        std::string                 tmp("");
        tmp.reserve(path.size());
        endings.reserve(path.size());

        for (unsigned int i = path.size() - 1; i != 0; --i) {
            const TCP1251TriePathTraits::TPathCell& cell(path[i]);

            if (Trie.IsStateAccepted(cell.EndOfEdge)) {
                endings.push_back(path.size() - i - 1);
            }

            tmp += cell.TransitionChar;
        }

        for (unsigned int i = 0; i < endings.size(); ++i) {

            std::string fullString(tmp.substr(endings[i]));

            for (unsigned int j = i + 1; j < endings.size(); ++j ) {
                std::cout   << "'" << fullString << "' : '"
                            << fullString.substr(0, endings[j] - endings[i]) << "' + '"
                            << fullString.substr(endings[j] - endings[i]) << "'" << std::endl;
            }

        }
    }

private:
    const TCP1251Trie& Trie;
};

typedef TTrieWalker<TCP1251Trie, TPathPrinter>  TCP1251TriePathPrinter;


int main( int /*argc*/, char** /*argv*/ )
{
    std::vector<std::string>    testStrings;

//    testStrings.push_back(   "umper");
//    testStrings.push_back(  "bumper");
//    testStrings.push_back( "abumper");
    testStrings.push_back(   "a");
    testStrings.push_back(  "aa");
    testStrings.push_back(  "ac");
    testStrings.push_back( "aaa");
    testStrings.push_back("aaaa");
    testStrings.push_back("abaa");
    testStrings.push_back("acaa");
    testStrings.push_back(  "ca");
    testStrings.push_back(   "c");
    testStrings.push_back(  "cb");
    testStrings.push_back(  "cc");
    testStrings.push_back( "caa");
    testStrings.push_back("caaa");
    testStrings.push_back("cbaa");
    testStrings.push_back("ccaa");

    TCP1251Trie trie;

    for (unsigned int i = 0; i != testStrings.size(); ++i) {
        //check for non-existence
        std::cout << "before adding '" << testStrings[i] << "' : " << std::endl; 
        
        for (unsigned int j = 0; j != i; ++j) {
            const std::string& addedString(testStrings[j]);
            unsigned int state(checkChain( trie
                                         , addedString.rbegin()
                                         , addedString.rend() ));

            if ((TCP1251Trie::kInvalidState == state) or (not trie.IsStateAccepted(state))) {
                std::cout << "\tcannot find '" << addedString << "'" << std::endl;
                return 1;
            }
        }

        for (unsigned int j = i; j != testStrings.size(); ++j) {
            const std::string& addedString(testStrings[j]);
            unsigned int state(checkChain( trie
                                         , addedString.rbegin()
                                         , addedString.rend() ));

            if ((TCP1251Trie::kInvalidState != state) and (trie.IsStateAccepted(state))) {
                std::cout << "\tunexpextedly find '" << addedString << "'" << std::endl;
                return 1;
            }
        }

        const std::string& stringToAdd(testStrings[i]);

        if (TCP1251Trie::kInvalidState ==  addChain(trie, stringToAdd.rbegin(), --stringToAdd.rend(), TEmpty())) {
            std::cout << "\tcould not add '" << stringToAdd << "'" << std::endl;
            return 1;
        }
        else {
            std::cout << "\tOK" << std::endl;
        }
    }
    TPathPrinter            printer(trie);
    TCP1251TriePathPrinter  triePrinter(printer);
    triePrinter.Walk(trie);
    
    
    return 0;
}
